package cn.sciento.boot.tenant.processor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import cn.sciento.core.exception.CommonException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.util.CollectionUtils;

public class TenantInitGroupExecutor {
  private static final Logger LOGGER = LoggerFactory.getLogger(TenantInitGroupExecutor.class);

    public static <T, R> List<R> doGroupThenExecuteOrderly(AsyncTaskExecutor asyncTaskExecutor, List<T> rawDataList, TenantInitGroupExecutor.GroupBy<T> groupBy, TenantInitGroupExecutor.Execution<T, R> execution) {
        if (CollectionUtils.isEmpty(rawDataList)) {
            return Collections.emptyList();
        } else {
            Map<Object, List<T>> groupedDataMap = groupBy(rawDataList, groupBy);
            List<R> resultList = new ArrayList(16);
            groupedDataMap.forEach((key, valueList) -> {
                List<Future<R>> futureList = new ArrayList(8);
                valueList.forEach((item) -> {
                    Future<R> future = asyncTaskExecutor.submit(() -> {
                        R result = execution.doExecute(key, item);
                        return result;
                    });
                    futureList.add(future);
                });
                futureList.parallelStream().forEach((future) -> {
                    try {
                        resultList.add(future.get());
                    } catch (Exception var3) {
                        LOGGER.error("async do execute and await with error: ", var3);
                        throw new CommonException(var3);
                    }
                });
            });
            return resultList;
        }
    }

    /**
     * 通过聚合条件对list中的进行排序聚合，在接着进行调用相关的后续处理逻辑。相关的请求需要按照顺序执行
     * @param asyncTaskExecutor
     * @param rawDataList
     * @param groupBy
     * @param execution
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> doGroupThenExecuteGroupOrderly(AsyncTaskExecutor asyncTaskExecutor, List<T> rawDataList, TenantInitGroupExecutor.GroupBy<T> groupBy, TenantInitGroupExecutor.GroupExecution<T, R> execution) {
        if (CollectionUtils.isEmpty(rawDataList)) {
            return Collections.emptyList();
        } else {
            Map<Object, List<T>> groupedDataMap = groupBy(rawDataList, groupBy);
            List<R> resultList = new ArrayList(16);
            groupedDataMap.forEach((key, valueList) -> {
                Future future = asyncTaskExecutor.submit(() -> execution.doExecute(key, valueList));

                try {
                    resultList.addAll((Collection)future.get());
                } catch (Exception var7) {
                    LOGGER.error("async do execute group and await with error: ", var7);
                    throw new CommonException(var7);
                }
            });
            return resultList;
        }
    }

    /**
     * 通过聚合条件对list中的进行排序聚合，在接着进行调用相关的后续处理逻辑。相关的请求需要按照不需要安装顺序执行
     * @param asyncTaskExecutor
     * @param rawDataList
     * @param groupBy
     * @param execution
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> doGroupThenExecuteGroupWithoutOrder(AsyncTaskExecutor asyncTaskExecutor, List<T> rawDataList, TenantInitGroupExecutor.GroupBy<T> groupBy, TenantInitGroupExecutor.GroupExecution<T, R> execution) {
        if (CollectionUtils.isEmpty(rawDataList)) {
            return Collections.emptyList();
        } else {
            Map<Object, List<T>> groupedDataMap = groupBy(rawDataList, groupBy);
            List<Future<List<R>>> futureList = new ArrayList<>(16);
            groupedDataMap.forEach((key, valueList) -> {
                Future<List<R>> future = asyncTaskExecutor.submit(() -> execution.doExecute(key, valueList));
                futureList.add(future);
            });
            List<R> resultList = new ArrayList<>(16);
            futureList.forEach((future) -> {
                try {
                    resultList.addAll(future.get());
                } catch (Exception var3) {
                    LOGGER.error("async do execute group and await with error: ", var3);
                    throw new CommonException(var3);
                }
            });
            return resultList;
        }
    }
  
  private static <T> Map<Object, List<T>> groupBy(List<T> rawDataList, GroupBy<T> groupBy) {
    if (CollectionUtils.isEmpty(rawDataList))
      return Collections.emptyMap(); 
    Map<Object, List<T>> groupedDataMap = rawDataList.stream().collect(Collectors.groupingBy(groupBy::basedOn));
    return new TreeMap<>(groupedDataMap);
  }
  
  @FunctionalInterface
  public static interface GroupExecution<T, R> {
    List<R> doExecute(Object param1Object, List<T> param1List);
  }
  
  @FunctionalInterface
  public static interface Execution<T, R> {
    R doExecute(Object param1Object, T param1T);
  }
  
  @FunctionalInterface
  public static interface GroupBy<T> {
    Object basedOn(T param1T);
  }
}
